package com.ssy.lingxi.product.utils;

import java.io.*;
import java.util.zip.CRC32;
import java.util.zip.CheckedOutputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/**
 * @author jw.chen
 * @version 2.0.0
 * @description 压缩工具类
 * @date 2021/12/1
 */
public class ZipUtil {
    private static final int BUFFER_SIZE = 1024;
    private static final String PATH_SEP = "/";

    /**
     * 压缩文件
     * @param sourceFileName    源文件名
     * @param destFileName      目标文件名
     */
    public static void zipCompress(String sourceFileName, String destFileName) throws IOException {
        File sourceFile = new File(sourceFileName);
        File destFile = new File(destFileName);
        zipCompress(sourceFile, destFile);
    }

    /**
     * 压缩文件
     * @param sourceFile        源文件
     * @param destFile          目标文件
     */
    public static void zipCompress(File sourceFile, File destFile) throws IOException {
        FileOutputStream fos = null;
        CheckedOutputStream cos = null;
        ZipOutputStream zos = null;
        try {
            fos = new FileOutputStream(destFile);
            cos = new CheckedOutputStream(fos, new CRC32());
            zos = new ZipOutputStream(cos);
            zipCompress(sourceFile, zos, "");
            zos.flush();
            zos.finish();
        } finally {
            if (zos != null)
                zos.close();
            if (cos != null)
                cos.close();
            if (fos != null)
                fos.close();
        }
    }

    /**
     * 压缩文件
     * @param sourceFile        源文件
     * @param zos               输出流
     * @param basePath          路径
     */
    private static void zipCompress(File sourceFile, ZipOutputStream zos, String basePath) throws IOException {
        if (sourceFile.isDirectory())
            zipCompressDir(sourceFile, zos, basePath);
        else
            zipCompressFile(sourceFile, zos, basePath);
    }

    /**
     *  压缩目录
     * @param dir           目录文件
     * @param zos           输出流
     * @param basePath      路径
     */
    private static void zipCompressDir(File dir, ZipOutputStream zos, String basePath) throws IOException {
        File[] files = dir.listFiles();
        String newBasePath = basePath + dir.getName() + PATH_SEP;
        if (files.length <= 0) {
            ZipEntry entry = new ZipEntry(newBasePath);
            zos.putNextEntry(entry);
            zos.closeEntry();
        }
        for (File file : files) {
            zipCompress(file, zos, newBasePath);
        }
    }

    /**
     * 压缩文件
     * @param file     文件
     * @param zos      输出流
     * @param basePath 路径
     */
    private static void zipCompressFile(File file, ZipOutputStream zos, String basePath) throws IOException {
        String entryName = basePath + file.getName();
        FileInputStream fis = new FileInputStream(file);
        zipCompress(fis, zos, entryName);
    }

    /**
     *  压缩文件
     * @param is        输入流
     * @param zos       输出流
     * @param entryName 压缩包名
     */
    private static void zipCompress(InputStream is, ZipOutputStream zos, String entryName) throws IOException {
        BufferedInputStream bis = null;
        try {
            bis = new BufferedInputStream(is);
            ZipEntry entry = new ZipEntry(entryName);
            zos.putNextEntry(entry);
            int count;
            byte[] buffer = new byte[BUFFER_SIZE];
            while (true) {
                count = bis.read(buffer, 0, BUFFER_SIZE);
                if (count < 0)
                    break;
                zos.write(buffer, 0, count);
            }
            zos.closeEntry();
        } finally {
            if (bis != null)
                bis.close();
        }
    }
}
